home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 3: Developer Tools / Linux Cubed Series 3 - Developer Tools.iso / devel / lang / fortran / f2c-stab.9 / f2c-stab / f2c-stabs / f2c-stabs.el < prev    next >
Encoding:
Text File  |  1996-03-31  |  43.7 KB  |  1,205 lines

  1. ;; f2c-stabs - emacs aid for debugging fortran code compiled via f2c.
  2. ;;
  3. ;; Copyright (c) 1996 Harvey J. Stein <abel@netvision.net.il>, and
  4. ;; eventually <hjstein@netvision.net.il>
  5. ;; All Rights Reserved.
  6. ;; 
  7. ;; This package is covered by the GNU GPL.  You can freely use and
  8. ;; distribute it as long as it stays under the GNU GPL, and as long as
  9. ;; you distribute all the corresponding source code, and as long as this
  10. ;; message and the above copyright notice remains.
  11. ;;
  12. ;; Introduction
  13. ;; ------------
  14. ;; Annoyances exist when using gdb to debug fortran code compiled via
  15. ;; f2c.  The problems are:
  16. ;;   -Name mangling.
  17. ;;       f2c mangles variable names in an effort to avoid name
  18. ;;       collisions.  For example, a local variable foo_bar must be
  19. ;;       accessed as foo_bar__ in gdb.  Worse is the common block
  20. ;;       handling.  Common blocks become global structures.  Variables
  21. ;;       foo and foo_x in common block bar must be accessed as
  22. ;;       bar_.foo and foo_.bar_x__, respectively.  This makes
  23. ;;       inspecting variable values annoying.
  24. ;;   -Array accessing.
  25. ;;       f2c declares all arrays to be 1 dimensional C arrays, and
  26. ;;       computes array indices by itself.  Sometimes, it will shift
  27. ;;       pointers around to avoid the need to add an offset when
  28. ;;       computing indices.  This makes it difficult to use gdb to
  29. ;;       determine the value of an array at a particular index -
  30. ;;       especially if the array is multidimensional.
  31. ;;   -Argument dereferencing.
  32. ;;       Aside from the above name mangling, local variables are
  33. ;;       accessed normally.  However, since arguments are passed by
  34. ;;       reference, when one inspects the values of arguments one must
  35. ;;       dereference them using the * operator.
  36. ;;   -Parameter access.
  37. ;;       f2c realizes the parameters - they never make it into the C
  38. ;;       code, and thus aren't visible to gdb.
  39. ;;
  40. ;; The correct solution to the above would be to 
  41. ;;    a) alter the stab data in the .o files to properly reflect
  42. ;;       common block names, and
  43. ;;    b) teach gdb about f2c's name mangling.
  44. ;;
  45. ;; This could prove quite tricky and no one's bothered to do it yet.
  46. ;;
  47. ;; This file is a work-around for the above.  It gives functions for
  48. ;; loading symbol table data into emacs, teaches emacs f2c's name
  49. ;; mangling, and gives functions for interacting with gdb (when run
  50. ;; from within emacs) so that the above problems can be partially
  51. ;; circumvented.
  52. ;;
  53. ;; Usage
  54. ;; -----
  55. ;; (Make sure you read everything below before starting.  This could
  56. ;; be crucial to your sanity).
  57. ;;
  58. ;; When debugging, one can type a fortran expression into gdb, and
  59. ;; then do M-x f2c-gdb.  The f2c-gdb function prompts for a fortran
  60. ;; expression (keeping a history of the expressions you've evaluated)
  61. ;; converts it to the corresponding C code (that gdb can understand),
  62. ;; and asks gdb to evaluate it.  Thus, the value of the expression
  63. ;; appears in your gdb buffer.
  64. ;;
  65. ;; I typically bind this command to C-cC-v (V for Variable reference).
  66. ;;
  67. ;; Note that the Fortran expression can be any expression, as long as
  68. ;; it doesn't use exponentiation.
  69. ;;
  70. ;; For example, after giving the f2c-gdb command, one will see in the
  71. ;; minibuffer:
  72. ;;
  73. ;;    Evaluate expression: 
  74. ;;
  75. ;; If you type in:
  76. ;;
  77. ;;          mat3[1,2,3]
  78. ;;
  79. ;; and hit return, f2c-gdb will look into the symbol tables to
  80. ;; determine how to access mat3(1,2,3), and will get gdb to print its
  81. ;; value.  After the command, the gdb interaction buffer will display
  82. ;; something like: 
  83. ;;
  84. ;; (mat3[1,2,3]) = 16.123
  85. ;; (gdb)
  86. ;;
  87. ;; Note that f2c-gdb allows index ranging.  This means that f2c-gdb
  88. ;; will take things like the following expression:
  89. ;;
  90. ;;       mat3[2*(1:3)-1, 2:3, -2:-1]
  91. ;;
  92. ;; and cause gdb to display something like:
  93. ;; (mat3[((2*1)-1),2,-2]) = 123.121256    
  94. ;; (mat3[((2*2)-1),2,-2]) = 0             
  95. ;; (mat3[((2*3)-1),2,-2]) = 0             
  96. ;; (mat3[((2*1)-1),3,-2]) = 123.121256    
  97. ;; (mat3[((2*2)-1),3,-2]) = 123.121256    
  98. ;; (mat3[((2*3)-1),3,-2]) = 123.126       
  99. ;; (mat3[((2*1)-1),2,-1]) = 123.126       
  100. ;; (mat3[((2*2)-1),2,-1]) = 133.1         
  101. ;; (mat3[((2*3)-1),2,-1]) = 133.1         
  102. ;; (mat3[((2*1)-1),3,-1]) = 133.1         
  103. ;; (mat3[((2*2)-1),3,-1]) = 0             
  104. ;; (mat3[((2*3)-1),3,-1]) = 19
  105. ;; (gdb)
  106. ;;
  107. ;; Note also that f2c-gdb allows indices to be expressions.  For
  108. ;; example, one could use f2c-gdb on:
  109. ;;
  110. ;;    mat3[i,j,type]
  111. ;;
  112. ;; or on:
  113. ;;
  114. ;;     mat3[-2:2,j,type]
  115. ;;
  116. ;; However, one may not use index ranging on an index containing a
  117. ;; variable.  So, vect[1:j] wouldn't work right.  Of course, one can
  118. ;; simulate things like vect[(j:j+10)] by vect[j+(0:10)].
  119. ;;
  120. ;; Note that the entire expression used is parsed and modified by
  121. ;; f2c-gdb before passing it back to gdb for evaluation.  Therefore,
  122. ;; one can nest things to one's hearts content.  For example, f2c-gdb
  123. ;; can handle expressions such as:
  124. ;;
  125. ;;     temp[bad_times[1:10], 1] - base_temp
  126. ;;
  127. ;; Setup
  128. ;; -----
  129. ;; Unfortunately, the above functionality comes at a price.  As I
  130. ;; mentioned above, one must load the symbol table data into emacs.
  131. ;; 
  132. ;; Fortunately, there are tools for building the appropiate lisp
  133. ;; files.  If you have all the .f and .inc files that comprise your
  134. ;; code in the current directory, *and*, you don't have any .el files
  135. ;; that you need to keep around, then you can do:
  136. ;;
  137. ;;   rm *.el
  138. ;;   fts-f2si *.f *.inc
  139. ;;   make-f2c-stabs *.si
  140. ;;
  141. ;; The fts-f2si command reads all the Fortran files specified on the
  142. ;; command line and makes corresponding .si files (stands for
  143. ;; Subroutine Information) which contain information such as the local
  144. ;; variables, their types and dimensions, names of included files,
  145. ;; variables in common blocks, etc.
  146. ;;
  147. ;; The make-f2c-stabs command reads the .si files and outputs the
  148. ;; emacs elisp files needed for the f2c-gdb command.
  149. ;;
  150. ;; After doing this, everything should be automatic.  When you run gdb
  151. ;; from within emacs and give the f2c-gdb command, emacs will
  152. ;; automatically load all the necessary .el files from the current
  153. ;; directory.
  154. ;;
  155. ;; If things get munged, use the f2c-clear-stab-table to get emacs to
  156. ;; start from scratch again.
  157. ;;
  158. ;; If you don't have make-f2c-stabs, or can't get it to work (because
  159. ;; you didn't bother to download STk), you may use the following
  160. ;; functions to load the symbol table data into emacs:
  161. ;;
  162. ;; 
  163. ;; (f2c-add-common-var common var &optional dimens offsets)
  164. ;;   Tells emacs that var is a variable in the named common block
  165. ;;   common.  If var is an array, then dimens should be supplied and
  166. ;;   it should be a list of the ending indices of the variable.  If
  167. ;;   the variable has indices which don't start at 1, one supply the
  168. ;;   offsets argument, which should be a list of the starting indices.
  169. ;;   Note that var can be a list of symbols instead of just one
  170. ;;   symbol.  This makes it easier to load a group of arrays with the
  171. ;;   same dimensions, or all the scalars.
  172. ;;
  173. ;; For example, if one's fortran code contains:
  174. ;;
  175. ;;      INTEGER*2 foo(3,4)
  176. ;;      COMMON /bar_none/ foo
  177. ;;
  178. ;; one must give the command:
  179. ;;
  180. ;;   (f2c-add-common-var 'bar_none 'foo '(3 4))
  181. ;;
  182. ;; For the common block:
  183. ;;
  184. ;;      INTEGER*2 foo(3,-2:4)
  185. ;;      COMMON /bar_none/ foo
  186. ;;
  187. ;; one must give the command:
  188. ;;
  189. ;;   (f2c-add-common-var 'bar_none 'foo '(3 4) '(1 -2))
  190. ;;
  191. ;; 
  192. ;; Similarly, we have the functions:  
  193. ;;
  194. ;; (f2c-add-local-var context var &optional dimens offsets)
  195. ;;
  196. ;;    for adding local variables, and
  197. ;; 
  198. ;; (f2c-add-arg-var context var &optional dimens offsets)
  199. ;;
  200. ;;    for adding variables which are arguments.
  201. ;;
  202. ;; If you want to add a parameter (for convenient reference), use:
  203. ;;
  204. ;; (f2c-add-param context param value)
  205. ;;
  206. ;;
  207. ;; I must explain the above context argument.  All variable references
  208. ;; are interpreted with respect to the context in which they occur.
  209. ;; When the f2c-gdb command is given, it gets name of the function
  210. ;; that gdb is currently stopped in.  This function name is considered
  211. ;; to be the context in which symbols should be interpreted.  To
  212. ;; illustrate, here's some sample fortran code and the corresponding
  213. ;; symbol updating data:
  214. ;;
  215. ;;       SUBROUTINE EAT(FOOD, DRINK)
  216. ;;       REAL*8 FOOD(0:6, -5:10)
  217. ;;       REAL*8 DRINK(0:4, -5:8)
  218. ;; 
  219. ;;       REAL*8  RESULTS(-5:5, 9:12)
  220. ;;       REAL*8  MORE_RESULTS(5, 10)
  221. ;;       INTEGER NUM_RESULTS
  222. ;;       PARAMETER (NUM_RESULTS = 66)
  223. ;;       INTEGER YET_MORE_RESULTS(5, 10)
  224. ;;       REAL*8  ALT_RESULTS(-5:5, -NUM_RESULTS:NUM_RESULTS)
  225. ;;       COMMON  /FOOD_BLOCK/ ALT_RESULTS
  226. ;;
  227. ;; Here's how the above would be loaded into emacs:
  228. ;;
  229. ;;    (f2c-add-arg-var 'eat 'food  '(6 10) '(0 -5))
  230. ;;    (f2c-add-arg-var 'eat 'drink '(4 8)  '(0 -5))
  231. ;;    (f2c-add-local-var 'eat 'results '(5 12) '(-5 9))
  232. ;;    (f2c-add-local-var 'eat '(more_results yet_more_results)
  233. ;;                            '(5 10))
  234. ;;    (f2c-add-param 'eat 'num_results 66)
  235. ;;    (f2c-add-common-var 'food_block 'alt_results '(-5 "-num_results")
  236. ;;                        '(5 "num_results"))
  237. ;;    (f2c-add-subcontext 'food 'food_block)
  238. ;;
  239. ;; There are two new things above which I haven't yet discussed.
  240. ;; Instead of giving one variable, one may give a list of variables
  241. ;; (assuming they all have the same dimensions and are declared in the
  242. ;; same subroutine, etc).
  243. ;;
  244. ;; Secondly, note the call to f2c-add-subcontext.  Each context
  245. ;; contains a list of subcontexts.  When emacs tries to interpret a
  246. ;; symbol reference, it first looks in the variables declared for the
  247. ;; current context.  If it can't find the reference, it looks in the
  248. ;; variables declared for the subcontexts of the current context.
  249. ;; This is done recursively (although it probably needn't be), so be
  250. ;; careful not to define context loops.
  251. ;;
  252. ;; Simple usage
  253. ;; ------------
  254. ;; The easiest way to use the above is to ignore all the contexts.
  255. ;; Generate a file which adds *all* variables (except for common
  256. ;; blocks) to the context *globals*.  Add common block variables
  257. ;; as specified above, and make the common block names subcontexts of
  258. ;; *globals*.  Then, load f2c-stabs & this stab data file you just
  259. ;; generated from your .emacs.
  260. ;;
  261. ;; This will make all variables always accessable, because when
  262. ;; f2c-gdb sees a context that hasn't been loaded, it automatically
  263. ;; tries to load it.  If it cannot, it defines a context record with
  264. ;; no variables and with *globals* as its only subcontext.
  265. ;;
  266. ;; The only problem with this is that when two subroutines have the
  267. ;; same variable declared in different ways, one one will be
  268. ;; accessable.
  269. ;;
  270. ;; One could get around this problem by using lower level stab table
  271. ;; manipulation functions to make a pseudoname for one of the
  272. ;; variables.  If you're this sophisticated, you can look at the code
  273. ;; below to figure out how to do this.
  274. ;;
  275. ;; High tech usage
  276. ;; ----------------
  277. ;; The high tech way (and the way that make-f2c-stabs operates) is to
  278. ;; use the above is to add everything to it's proper context.  One can
  279. ;; either do this all in one file, and load it from your .emacs file,
  280. ;; or one could get *really* fancy by using the following f2c-gdb
  281. ;; feature.
  282. ;;
  283. ;; When f2c-gdb trys to resolve a symbol, it checks to see if the
  284. ;; current context has been loaded yet.  If it hasn't it gets the
  285. ;; current file name from gdb, and tries to load it as a .el file.
  286. ;; For example, if gdb is currently debugging foo.f, then f2c-gdb will
  287. ;; try to load foo.f.elc and then foo.f.el.  It will look first in the
  288. ;; current directory, and then along the load-path.
  289. ;;
  290. ;; So, rather than throwing all definitions into emacs at startup, you
  291. ;; can parse files on an individual basis - all the definitions in
  292. ;; foo.f into foo.f.el, and all the definitions in bar.f into bar.f.el.
  293. ;; Emacs will automatically load the corresponding lisp code when
  294. ;; needed.
  295. ;;
  296. ;; Note that I don't autoload recursively, so in particular, you
  297. ;; should load common block declarations either at startup or when you
  298. ;; start up gdb.
  299. ;;
  300. ;; So, a convenient setup would be as follows:
  301. ;; 
  302. ;; First process each include file.  Each include file foo.inc will
  303. ;; have a corresponding foo.inc.el.  Give each .inc its own context
  304. ;; (maybe with name equal to the name of the .inc file), and add all
  305. ;; the symbols in the .inc file as subcontexts for this context.
  306. ;; Then process each function.  Use (f2c-require 'foo.inc.el) at the
  307. ;; top of foobar.f.el if foobar.f includes foo.inc.  Within
  308. ;; foobar.f.el, use f2c-add-subcontext to add the inc's context to the
  309. ;; context for foobar.f.
  310. ;; 
  311. ;;
  312. ;; Useful utility routines
  313. ;; -----------------------
  314. ;; (f2c-resolve-ref context var)
  315. ;; Will traverse the symbol table data looking for a declaration of
  316. ;; var in the specified context.  Returns the declaration record, or
  317. ;; nul if it wasn't found.
  318. ;;
  319. ;; (f2c-resolve-expr context expr)
  320. ;;  Will return the parsed version of expr, relative to the given
  321. ;;  context.
  322. ;;
  323. ;; (f2c-resolve-and-expand context expr)
  324. ;;  As above, but also does range expansion, and unparses the
  325. ;;  expressions.
  326. ;;
  327. ;; (f2c-resolve-ref-in-current-context var)
  328. ;; As above, but queries gdb for current context.
  329. ;;
  330. ;; (f2c-local-symbol-name var)
  331. ;; Mangles var as f2c would when var is a local variable.
  332. ;;
  333. ;; (f2c-global-symbol-name var)
  334. ;; Mangles var as f2c would when var is a global variable (i.e. - an
  335. ;; entry point name or common block name).
  336. ;;
  337. ;; (f2c-common-symbol-name common var)
  338. ;; Returns the mangled name for accessing var, when var is a member of
  339. ;; the specified common block.
  340. ;;
  341. ;;
  342. ;; (f2c-get-context-stab context)
  343. ;; Returns the symbol table for the specified context.
  344. ;;
  345. ;; (f2c-get-or-load-context-stab context)
  346. ;; Same as f2c-get-context-stab, but will try to load it if CONTEXT
  347. ;; isn't yet recorded.  If it can't even be loaded, an empty context
  348. ;; will be created for CONTEXT, with subcontext *globals*.
  349. ;;
  350. ;;
  351. ;; To Do
  352. ;; -----
  353. ;;   -Better expression parsing.  Use symbol resolution recursively to
  354. ;;    allow things like:
  355. ;;       foo[bar[1:3], 1+baz[2:4,i]]   (done v1.0).
  356. ;;   -Write a tool to generate f2c-stabs data files  (done v1.0).
  357. ;;   -Figure out how to get the current function from gdb. (done v1.0,
  358. ;;    but sometimes breaks)
  359. ;;   -Not getting correct context after user does an up in gdb buffer
  360. ;;    (done v1.0).
  361. ;;
  362. ;;   -Problem with parameters whose values are formed by other
  363. ;;    parameters.  Suppose parameter foo_bar is (+ (* bar baz) 3).  Then
  364. ;;    we need to resolve bar and baz before passing things to gdb.
  365. ;;    Since foo_bar's value is in the long-name slot of the stab data, and
  366. ;;    since when we rewrite expressions, we replace symbols by their
  367. ;;    long names, this seems to indicate that we should do this
  368. ;;    recursively - i.e. - don't replace foo_bar by (longname foo_bar),
  369. ;;    replace it by (f2c-rewrite-symbols (longname foo_bar)).  However,
  370. ;;    we can't do this in general, because if foo_bar is a local
  371. ;;    variable (for example), its long name will be foo_bar__.  When
  372. ;;    we pass this to f2c-rewrite-symbols, f2c-rewrite-symbols will
  373. ;;    think that this is a local variable (because it won't be in the
  374. ;;    symbol tables, and will convert it to foo_bar____!  So
  375. ;;    basically, it seems like we need to recursively expand
  376. ;;    parameters, yet we need to avoid this for other symbols.
  377. ;;    Ways to handle this:
  378. ;;       -expand parameters when they're loaded instead of when
  379. ;;        they're evaluated.  This should be ok as long as the load
  380. ;;        files have the parameters in the correct order, because
  381. ;;        parameters have to ultimately resolve to a number at
  382. ;;        declaration time.  However, this requires a 2nd more recursive
  383. ;;        version of f2c-rewrite-symbols for use when loading syms.
  384. ;;       -Add a type field in the stabs data, and have
  385. ;;        f2c-rewrite-symbols do recursive expansion for parameters
  386. ;;        but not for other variables.  This will potentially make
  387. ;;        f2c-rewrite-symbols alot worse than it already is.
  388. ;;    (sort of done v1.0 with an quick ugly hack - I followed the
  389. ;;    first way, but instead of writing a proper version of
  390. ;;    f2c-rewrite-symbols for it, I merely call the normal version
  391. ;;    over and over again until it either it doesn't change the
  392. ;;    expression or until I've called it 10 times.  I said it was
  393. ;;    ugly...)
  394. ;;
  395. ;;   -Entry points might not work so well...
  396. ;;
  397. ;;   -Even better expression parsing.  parcil doesn't quite match
  398. ;;    Fortran, tries to interpret "1d100" in elisp (which basically
  399. ;;    gets converted to a random number), and chokes on ".7".  A big
  400. ;;    plus would be had if one could convince parcil to deal with .7,
  401. ;;    and to leave all non-integer numbers alone (return them as
  402. ;;    strings).  You want to evaluate the integers so that expression
  403. ;;    reduction can be done.
  404. ;;
  405. ;;   Performance hacks one might or might not want to do.  It's not
  406. ;;   clear that all would work, or even that one would want to do
  407. ;;   these things.  For example, it might be tricky to avoid order
  408. ;;   dependencies when doing the first one.
  409. ;;   -It would be clever to make the subcontext list a list of
  410. ;;    pointers into other contexts, rather than a list of the symbol
  411. ;;    names of other contexts - would avoid alot of list scanning.
  412. ;;   -It would be clever to both do the above and to make the contexts
  413. ;;    themselves emacs variables.  Maybe context would correspond to
  414. ;;    variable *f2c-stabs:context*.  Or, *f2c-stabs* could be an
  415. ;;    obarray to use instead...  Do this and *all* scanning for
  416. ;;    contexts would be circumvented.
  417. ;;   -For *real* *hot* operation, hang all variable declarations off
  418. ;;    of symbols too.  Then, just access *f2c-stabs:context:variable*
  419. ;;    for the variable declaration.  If it doesn't exist, get the
  420. ;;    subcontext list from *f2c-stabs:context*, and check for the
  421. ;;    variable in the contexts listed.
  422. ;;   -The above hacks might be needed for really large symbol tables,
  423. ;;    but in that the symbol table is only scanned upon user
  424. ;;    invocation of f2c-gdb, it probably isn't necessary.
  425. ;;   -Integrate f2c-gdb into gud - get emacs to filter everything that
  426. ;;    gets passed to gdb, and do variable lookups and de-referencing
  427. ;;    on the fly.  This would be way cool.
  428.  
  429. (require 'parcil)
  430. (require 'cl)
  431. (require 'cl-19)
  432.  
  433. (if (< max-lisp-eval-depth 800)
  434.     (setq max-lisp-eval-depth 800))
  435.  
  436.  
  437. (defvar *f2c-stabs* '((*globals* () ())))
  438. ;;  Format is:
  439. ;; '((context ( (sub-c sub-c sub-c ...) (local-stab-table)))
  440. ;;   (context ( (sub-c sub-c sub-c ...) (local-stab-table)))
  441. ;;   ...))
  442. ;;  Local stab table format:
  443. ;;  ((var full-name dimen offset dereferencer)
  444. ;;   (var full-name dimen offset dereferencer)
  445. ;;   ...)
  446.  
  447. (defvar *f2c-require-list* ())
  448. ;; List of files that we've already loaded.  I don't use
  449. ;; require/provide, because of the way it uses symbols and because I
  450. ;; want to only load foo.f.elc & foo.f.el.  I don't want emacs to
  451. ;; strip the suffix and try to load foo.f. 
  452.  
  453.  
  454. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  455. ;;; Low level stab table manipulation.
  456. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  457.  
  458. (defun f2c-get-or-load-context-stab (context)
  459.   "Retreive a context-stab.  Load or create a dummy record if CONTEXT
  460. isn't known"
  461.   (let* ((cont-stab (f2c-get-context-stab context)))
  462.     (cond (cont-stab            ; Context known.
  463.        cont-stab)
  464.       (t                ; Context unknown.  Try to load it.
  465.        (f2c-require (f2c-current-file))
  466.        (setq cont-stab (assoc context *f2c-stabs*))
  467.        (cond (cont-stab        ; Context now know.
  468.           cont-stab)
  469.          (t            ; Context still unknown.  Make it up.
  470.           (f2c-add-subcontext context '*globals*)
  471.           (assoc context *f2c-stabs*)))))))
  472.  
  473. (defun f2c-require (file)
  474.   (cond ((not (memq file *f2c-require-list*))
  475.      (let ((load-path (cons () load-path)))
  476.        (setq load-path (cons () load-path))
  477.        (if (or (load (concat (symbol-name file) ".elc")
  478.              t () t)
  479.            (load (concat (symbol-name file) ".el")
  480.              t () t))
  481.            (setq *f2c-require-list*
  482.              (cons file *f2c-require-list*)))))))
  483.  
  484.  
  485. (defun f2c-get-context-stab (context)
  486.   "Gets full stab table for CONTEXT."
  487.   (assoc context *f2c-stabs*))
  488.  
  489. (defun f2c-context (context-stab)
  490.   "Gets context name from a stab table CONTEXT-STAB."
  491.   (nth 0 context-stab))
  492.  
  493. (defun f2c-subcontext (context-stab)
  494.   "Gets subcontext list from a stab table CONTEXT-STAB."
  495.   (nth 1 context-stab))
  496.  
  497. (defun f2c-stab-table (context-stab)
  498.   "Gets variable declaration list from stab table CONTEXT-STAB."
  499.   (nth 2 context-stab))
  500.  
  501. (defun f2c-var-data (stab-table var)
  502.   "Looks in STAB-TABLE for declaration record for VAR."
  503.   (assoc var stab-table))
  504.  
  505.  
  506. ;;; Breaking out data from a var record.
  507. (defun f2c-var-name (var-data)
  508.   (nth 0 var-data))
  509.  
  510. (defun f2c-long-name (var-data)
  511.   (nth 1 var-data))
  512.  
  513. (defun f2c-dimen (var-data)
  514.   (nth 2 var-data))
  515.  
  516. (defun f2c-offset (var-data)
  517.   (nth 3 var-data))
  518.  
  519. (defun f2c-aref (var-data)
  520.   (nth 4 var-data))
  521.  
  522.  
  523. ;;; Adding data
  524. (defun f2c-add-context (context)
  525.   "Creates the specified context if it doesn't exist."
  526.   (if (not (assoc context *f2c-stabs*))
  527.       (setq *f2c-stabs* (cons (list context nil nil)
  528.                   *f2c-stabs*))))
  529.  
  530.  
  531. (defun f2c-get-or-add-context (context)
  532.   "Gets full stab table for specified context.  Creates the context if it doesn't exist."
  533.   (let ((context-stab (f2c-get-context-stab context)))
  534.     (cond ((not context-stab)
  535.        (f2c-add-context context)
  536.        (setq context-stab (f2c-get-context-stab context))))
  537.     context-stab))
  538.  
  539. (defun f2c-add-subcontext (context sub-context)
  540.   (let ((context-stab (f2c-get-or-add-context context)))
  541.     (if (not (member sub-context (f2c-subcontext context-stab)))
  542.     (setcdr context-stab
  543.         (list (cons sub-context
  544.                 (f2c-subcontext context-stab))
  545.               (f2c-stab-table context-stab))))))
  546.  
  547.  
  548. (defun f2c-add-symbol (context var full-name &optional dimens offsets converter)
  549.   "Args: (context var full-name &optional dimens offsets converter).
  550. Adds specified var data to specified context.  Dimens is a list of the full
  551. length of each dimension of the variable - nil if the var is not an array.
  552. If the var is an array, offsets is the starting indices of the array.  Nil
  553. indicates that all indices start at 1.  Var and full-name can be lists
  554. of variables instead of just symbols.  The effect is to cause
  555. f2c-add-symbol to add each var/full-name pair."
  556.   (when (or (not (listp var))
  557.         (not (listp full-name)))
  558.     (setq var (list var))
  559.     (setq full-name (list full-name)))
  560.   (let ((context-stab (f2c-get-or-add-context context)))
  561.     (mapcar* '(lambda (var full-name)
  562.         (if (not (assoc var (f2c-stab-table context-stab)))
  563.             (setcdr context-stab
  564.                 (list (f2c-subcontext context-stab)
  565.                   (cons (f2c-make-stab-record
  566.                      context var full-name
  567.                      dimens offsets converter)
  568.                     (f2c-stab-table
  569.                      context-stab))))))
  570.          var
  571.          full-name)))
  572.  
  573. (defun f2c-make-stab-record (context var full-name dimens offsets converter)
  574.   "Args: (context var full-name dimens offsets converter).
  575. Makes a symbol table record containing the above data.  Dimens and
  576. offsets are resolved in the specified context."
  577.   (list var
  578.     full-name 
  579.     (mapcar 'f2c-parse-dimension-part dimens)
  580.     (mapcar 'f2c-parse-dimension-part offsets)
  581.     converter))
  582.  
  583. (defun f2c-parse-dimension-part (dim)
  584.   "Parses DIM, being careful about cases that DIM isn't a string, or
  585. is an asterisk."
  586.   (cond ((numberp dim)
  587.      dim)
  588.     ((string-match "^[ \t]*\\*[ \t]*$" dim)
  589.       1)                ; A hack, but it works...
  590.     (t
  591.      (f2c-reduce (parcil dim)))))
  592.  
  593. ;;(defun mapcar* (f &rest args)
  594. ;;  "Apply FUNCTION to successive cars of all ARGS, until one ends.
  595. ;;Return the list of results."
  596. ;;  (if (not (memq 'nil args))              ; If no list is exhausted,
  597. ;;      (cons (apply f (mapcar 'car args))  ; Apply function to CARs.
  598. ;;        (apply 'mapcar* f             ; Recurse for rest of elements.
  599. ;;           (mapcar 'cdr args)))))
  600.  
  601. (defun f2c-clear-stab-table ()
  602.   "Clears stabs tables (in case they need to be reloaded."
  603.   (interactive)
  604.   (setq *f2c-stabs* '((*globals* () ())))
  605.   (setq *f2c-require-list* '()))
  606.  
  607. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  608. ;;; High level interface.
  609. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  610.  
  611. ;;; Adding data
  612. (defun f2c-add-common-var (common var &optional dimens offsets)
  613. "Adds COMMON as a f2c context, and adds VAR as a common block variable
  614. in this context.  If DIMENS are given it should be a list of the upper
  615. bounds of the indices of VAR.  In this case, VAR is assumed to be an
  616. array.  If OFFSETS is given, it should be a list of the lower bounds
  617. of the indices of VAR.  If OFFSETS isn't given, it's assumed that the
  618. lower bounds are all one.  VAR may be a list of symbols, in which case
  619. each one is added."
  620.   (if (not (listp var)) (setq var (list var)))
  621.   (f2c-add-symbol common
  622.           var
  623.           (mapcar '(lambda (v)
  624.                  (f2c-common-symbol-name common v))
  625.               var)
  626.           (f2c-array-width dimens offsets)
  627.           offsets
  628.           'common-aref-form))
  629.  
  630.  
  631. (defun f2c-add-local-var (context var &optional dimens offsets)
  632. "Adds CONTEXT as a f2c context, and adds VAR as a local variable in
  633. this context.  If DIMENS are given it should be a list of the upper
  634. bounds of the indices of VAR.  In this case, VAR is assumed to be an
  635. array.  If OFFSETS is given, it should be a list of the lower bounds
  636. of the indices of VAR.  If OFFSETS isn't given, it's assumed that the
  637. lower bounds are all one.  VAR may be a list of symbols, in which case
  638. each one is added."
  639.   (if (not (listp var)) (setq var (list var)))
  640.   (f2c-add-symbol context
  641.           var
  642.           (mapcar 'f2c-local-symbol-name var)
  643.           (f2c-array-width dimens offsets)
  644.           offsets
  645.           'common-aref-form))
  646.  
  647. (defun f2c-add-arg-var (context var &optional dimens offsets)
  648. "Adds CONTEXT as a f2c context, and adds VAR as a subroutine argument
  649. in this context.  If DIMENS are given it should be a list of the upper
  650. bounds of the indices of VAR.  In this case, VAR is assumed to be an
  651. array.  If OFFSETS is given, it should be a list of the lower bounds
  652. of the indices of VAR.  If OFFSETS isn't given, it's assumed that the
  653. lower bounds are all one.  VAR may be a list of symbols, in which case
  654. each one is added."
  655.   (if (not (listp var)) (setq var (list var)))
  656.   (f2c-add-symbol context
  657.           var
  658.           (if dimens
  659.               (mapcar 'f2c-local-symbol-name var)
  660.             (mapcar 'f2c-arg-symbol-name var))
  661.           (f2c-array-width dimens offsets)
  662.           offsets
  663.           'base-aref-form))
  664.  
  665. (defun f2c-add-param (context param value)
  666. "Adds CONTEXT as a f2c context, and adds PARAM as a parameter in this
  667. context having value VALUE.  gdb-f2c will replace top level
  668. occurrences of PARAM with VALUE.  NOTE - unlike the other f2c-add
  669. functions, PARAM may NOT be a list."
  670.   (f2c-add-symbol context
  671.           param
  672.           ;; Too few hacks would make jack a dull boy...
  673.           (f2c-parse-param-guy context value)
  674. ;;;          value
  675.           nil
  676.           nil
  677.           nil))
  678.  
  679. ;;; The following is used to parse parameter values.  We don't just
  680. ;;; call parcil, because it barfs on things like ".7".  This will
  681. ;;; hopefully allow gdb to evaluate such things instead.
  682. ;;; Unfortunately, if the user sticks .7 or 1d100 into his expression, he's doomed...
  683. (defun f2c-parse-param-guy (context v)
  684.   (cond ((numberp v)
  685.      v)
  686.     ((string-match "^[+-]?[0-9]+*[ \t]*$" v) ; an integer
  687.      (string-to-number v))
  688.      ;; Nasty regexp which hopefully matches arithmetical expressions, but leaves variables alone...
  689.     ((string-match "^\\([ \t()+*/-]*[+-]?\\(\\([0-9]+\\.?[0-9]*\\|[0-9]*\\.[0-9]+\\)\\([dDeE][+-]?[0-9]+\\)?\\)[ \t()+*/-]*\\)*$" v)
  690.       v)
  691.     (t (do* ((i 1 (1+ i))
  692.          (oldpv () pv)
  693.          (pv (f2c-reduce (parcil v))
  694.              (f2c-reduce (f2c-rewrite-symbols context pv))))
  695.            ((or (> i 10) (equal pv oldpv)) pv)))))
  696.           
  697.  
  698. (defun f2c-resolve-ref-in-current-context (var)
  699.   "Returns the variable declaration data for VAR from the current context."
  700.   (f2c-resolve-ref (gud-context) var))
  701.  
  702. (defun f2c-resolve-ref (context var)
  703.   "Returns the variable declaration data from context CONTEXT for
  704. variable VAR."
  705.   (let* ((context-stab (f2c-get-or-load-context-stab context))
  706.      (vd (f2c-var-data (f2c-stab-table context-stab) var)))
  707.     (if vd
  708.     vd
  709.       (f2c-resolve-in-subcontext (f2c-context context-stab) var))))
  710.  
  711. (defun f2c-resolve-in-subcontext (context var)
  712.   (let* ((context-stab (f2c-get-context-stab context))
  713.      (vd (f2c-var-data (f2c-stab-table context-stab) var))
  714.      (subcs (f2c-subcontext context-stab)))
  715.     (if vd
  716.     vd
  717.       (while (and subcs (not vd))
  718.     (setq vd (f2c-resolve-in-subcontext (car subcs) var))
  719.     (setq subcs (cdr subcs)))
  720.       vd)))
  721.  
  722.  
  723. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  724. ;;; Name mangling
  725. ;;;    Routines for converting fortran symbols to their f2c mangled
  726. ;;;    versions.
  727. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  728.  
  729. (defun f2c-local-symbol-name (var)
  730.   "If it has an underscore, append 2!"
  731.   (let ((sv (symbol-name var)))
  732.     (if (string-match "_" sv)
  733.     (intern (concat sv "__"))
  734.       var)))
  735.  
  736. (defun f2c-localize-name (var)
  737.   (cond ((numberp var)
  738.      var)
  739.     ((symbolp var)
  740.      (f2c-local-symbol-name var))
  741.     (t
  742.      (f2c-local-symbol-name (intern var)))))
  743.  
  744.  
  745. (defun f2c-global-symbol-name (var)
  746.   "If it has an underscore, append 2, otherwise append 1."
  747.   (let ((sv (symbol-name var)))
  748.     (if (string-match "_" sv)
  749.     (intern (concat sv "__"))
  750.       (intern (concat sv "_")))))
  751.  
  752.  
  753. (defun f2c-common-symbol-name (common var)
  754.   "Return symbol name for accessing var from common."
  755.   (intern (concat (symbol-name (f2c-global-symbol-name common))
  756.           "."
  757.           (symbol-name (f2c-local-symbol-name var)))))
  758.  
  759. (defun f2c-arg-symbol-name (var)
  760.   "Same as local symbol name, but dereference it!"
  761.   (intern (concat "*"
  762.           (symbol-name (f2c-local-symbol-name var)))))
  763.  
  764. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  765. ;;; Array ref functions.
  766. ;;;   Functions which convert array indices to an offset.
  767. ;;;   Note that instead of actually computing the offset, these
  768. ;;;   routines return a C expression which gdb can evaluate.
  769. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  770.  
  771. (defun base-aref-form (dim index &optional offset)
  772.   "Returns a FORTRAN expression for computing the linear aref of a
  773. shifted f2c array with dimension list DIM at index (list) INDEX.  The
  774. optional argument OFFSET is ignored, but is included to make the
  775. calling sequence identical to that of the function common-aref."
  776.   (cond ((null index) 0)
  777.     (t (ftn-f+ (car index)
  778.           (ftn-f* (car dim)
  779.          (base-aref-form (cdr dim) (cdr index)))))))
  780.  
  781. (defun common-aref-form (dim index &optional offset)
  782.   "Returns a FORTRAN expression for computing the offset into an
  783. unshifted f2c array with dim list DIM of index INDEX.  If offset is
  784. supplied, it is used as the list of base indices for the array (as
  785. opposed to the default of 1)." 
  786.   (ftn-f- (base-aref-form dim index) (common-offset-form dim offset))) 
  787.  
  788. (defun common-offset-form (dim &optional offset)
  789.   "Returns a FORTRAN expression for computing the offset of the first
  790. element of a common block f2c array from index 0.  If the OFFSET list
  791. is supplied, assumes array dimensions start at OFFSET instead of (1 1 ...)."
  792.   (if (null offset) (setq offset (make-list (length dim) 1)))
  793.   (base-aref-form dim offset))
  794.  
  795. (defun ftn-form-f+ (a b)
  796.   (cond ((and (equal a 0) (equal b 0)) 0)
  797.     ((equal a 0) b)
  798.     ((equal b 0) a)
  799.     ((and (numberp a) (numberp b)) (+ a b))
  800.     (t  (format "(%s)+(%s)" a b))))
  801.  
  802. (defun ftn-form-f- (a b)
  803.   (cond ((and (equal a 0) (equal b 0)) 0)
  804.     ((equal a 0) (format "-(%s)" b))
  805.     ((equal b 0) a)
  806.     ((and (numberp a) (numberp b)) (- a b))
  807.     (t (format "(%s)-(%s)" a b))))
  808.  
  809. (defun ftn-form-f* (a b)
  810.   (cond ((or (equal a 0) (equal b 0)) 0)
  811.     ((equal a 1) b)
  812.     ((equal b 1) a)
  813.     ((and (numberp a) (numberp b)) (* a b))
  814.     (t (format "(%s)*(%s)" a b))))
  815.  
  816. (defun ftn-f+ (a b)
  817.   (cond ((and (equal a 0) (equal b 0)) 0)
  818.     ((equal a 0) b)
  819.     ((equal b 0) a)
  820.     ((and (numberp a) (numberp b)) (+ a b))
  821.     (t  (list '+ a b))))
  822.  
  823. (defun ftn-f- (a b)
  824.   (cond ((and (equal a 0) (equal b 0)) 0)
  825.     ((equal a 0) (list '- b))
  826.     ((equal b 0) a)
  827.     ((and (numberp a) (numberp b)) (- a b))
  828.     (t (list '- a b))))
  829.  
  830. (defun ftn-f* (a b)
  831.   (cond ((or (equal a 0) (equal b 0)) 0)
  832.     ((equal a 1) b)
  833.     ((equal b 1) a)
  834.     ((and (numberp a) (numberp b)) (* a b))
  835.     (t (list '* a b))))
  836.  
  837. (defun f2c-array-width (dimens &optional offsets)
  838.   (cond ((null dimens) ())
  839.     (t (cons (f2c-one-width (car dimens) (car offsets))
  840.          (f2c-array-width (cdr dimens) (cdr offsets))))))
  841.  
  842. (defun f2c-one-width (d &optional o)
  843.   (cond ((null o) d)
  844.     ((equal o 1) d)
  845.     ((and (stringp o) (string-match "^[ \t]*1[ \t]*$" o))
  846.      d)
  847.     ((and (stringp d) (string-match "^[ \t]*\\*[ \t]*$" d))
  848.      (error "f2c: Hit a bad dimension - check your f2c-stabs .el files."))
  849.     (t (ftn-form-f+ 1 (ftn-form-f- d o)))))
  850.  
  851. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  852. ;;; Routines for snarfing symbols off of the current line
  853. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  854.  
  855. (defun f2c-snarf ()
  856.   "Reads expression from current line.  Return it as a string."
  857.   (save-excursion
  858.     (let* ((b (progn (beginning-of-line) (point-marker)))
  859.        (e (progn (end-of-line) (point-marker))))
  860.       (goto-char b)
  861.       (if (not (re-search-forward "\\([^ \t]*[ \t]+\\)\\(.*\\)[ \t]*$" (1+ e) t))
  862.       ()
  863.     (let* ((md (match-data))
  864.            (lmd (length md)))
  865.       (buffer-substring (nth (- lmd 2) md)
  866.                 (nth (- lmd 1) md)))))))
  867.  
  868. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  869. ;;; Interacting with gud.
  870. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  871.  
  872. (defun f2c-current-file ()
  873.   "Queries gud for current file.  Result returned as a symbol."
  874.   (intern (gud-current-file)))
  875.  
  876. (defun gud-current-file ()
  877.   "Returns the file gud is currently in."
  878.   (let ((frame (or gud-last-frame gud-last-last-frame)))
  879.     (if (null (car frame))
  880.     ""
  881.       (file-name-nondirectory (car frame)))))
  882.  
  883. (defun gdb-context ()
  884.   "Gets symbol name of current fcn from gdb.  Downcase it because
  885. Fortran is not case sensitive.  Really ugly parsing of gdb response to
  886. frame command."
  887.   (let ((cur-frame (gud-info-command "frame")))
  888.     ;; regexp to parse subroutine name out of gdb's response to frame
  889.     ;; command.  Expect a line beginning with #<number>, followed
  890.     ;; possibly by garbage (stack pointer?), followed by space,
  891.     ;; subroutine name space open parenthesis.  At least, this is what
  892.     ;; it seems to be.  Is this really the case?
  893.     (cond ((string-match "^#[0-9]+.* \\([^ \t]+\\) ("
  894.              cur-frame)
  895.        (setq cur-frame (substring cur-frame
  896.                       (match-beginning 1)
  897.                       (match-end 1)))
  898.        ;; Note the call to demangle-global.
  899.        (intern (downcase (f2c-demangle-global cur-frame))))
  900.       (t '*globals*))))
  901.  
  902. (fset 'gud-context (symbol-function 'gdb-context))
  903.  
  904. ;; Special demangling for subroutine names because of the way f2c
  905. ;; deals with entry points.  If you have a subroutine foo_bar and entry
  906. ;; point foo_eat, you get 3 subroutines, foo_bar__, foo_bar__0_ and
  907. ;; foo_eat__.  The routines foo_bar__ and foo_eat__ just call
  908. ;; foo_bar__0_, so most of the time your actually in foo_bar__0_.
  909. ;; Thus, we special case this out, converting foo_bar__0_ to foo_bar,
  910. ;; which is the name of the context that the user would have used for
  911. ;; the symbols in both foo_bar and foo_eat.  Note, however, that there
  912. ;; are other problems involved.  If the entry point has 
  913.  
  914. (defun f2c-demangle-global (name)
  915.   (cond ((string-match ".*__0_$" name)
  916.      (substring name 0 (- (length name) 4)))
  917.     ((string-match ".*_0_$" name)
  918.      (substring name 0 (- (length name) 3)))
  919.     ((string-match ".*__$" name)
  920.      (substring name 0 (- (length name) 2)))
  921.     (t
  922.      (substring name 0 (- (length name) 1)))))
  923.  
  924. ;;; The following should be in gud...
  925. (defvar gud-info-in-progress ())
  926. (defvar gud-info-string "")
  927.  
  928. ;;; According to the comments in gud.el, setting
  929. ;;; gud-delete-prompt-marker to point nowhere should prevent
  930. ;;; gud-basic-call from deleting the current prompt.  We want this
  931. ;;; because we're going to snarf up all the data.  However, this
  932. ;;; doesn't seem to work, so instead we'll have to save the old
  933. ;;; prompt, and reinsert it later.  The problem is that gud-basic-call
  934. ;;; resets gud-delete-prompt-marker automatically, so we don't get any
  935. ;;; control...  Thus, we can't use gud-basic-call, and must do the
  936. ;;; call by hand...  This should be included in gud.el - it'd allow
  937. ;;; much easier customization - people would be able to easily write
  938. ;;; elisp fcns to send commands to gud & interpret the results.  This
  939. ;;; would, for example, effectively give gdb a (cheezy) scripting
  940. ;;; language.
  941. (defun gud-info-command (command)
  942.   "Send CMD to gud and return result as a string.  Result includes the
  943. prompt at the end."
  944.   (interactive)
  945.   (let* ((end (point))
  946.      (old-filter (symbol-function 'gud-marker-filter))
  947.          (gud-delete-prompt-marker (make-marker)))
  948.     (unwind-protect
  949.     (progn
  950.       ;; Temporarily install our filter function.
  951.       (gud-overload-functions
  952.        '((gud-marker-filter . gud-info-filter)))
  953.       ;; Issue the command to GDB.
  954.       (gud-set-buffer)
  955.       (process-send-string (get-buffer-process gud-comint-buffer)
  956.                    (format "%s\n" command))
  957.       (setq gud-info-in-progress t
  958.         gud-info-string "")
  959.       ;; Slurp the output.
  960.       (while gud-info-in-progress
  961.         (accept-process-output (get-buffer-process gud-comint-buffer))))
  962.       ;; Restore the old filter function.
  963.       (fset 'gud-marker-filter old-filter))
  964.     ;; Protect against old versions of GDB.
  965.     gud-info-string))
  966.  
  967. (defun gud-info-filter (string)
  968.   (setq gud-info-string (concat gud-info-string string))
  969.   (if (string-match comint-prompt-regexp gud-info-string)
  970.       (progn
  971.     (setq gud-info-in-progress nil)
  972.     "")
  973.     ""))
  974.  
  975. (defun gud-empty-filter (string)
  976.   string)
  977.  
  978.  
  979. (defun f2c-rewrite-symbols (context l)
  980.   "Rewrites symbols in parsed expression list L."
  981.   (cond ((null l) ())
  982.     ((atom l) (let ((v (f2c-resolve-ref context l)))
  983.             (if v (f2c-long-name v)
  984.               (f2c-localize-name l))))
  985.     ((eq (car l) 'aref)        ; Convert refs.
  986.      (let ((v (f2c-resolve-ref context (nth 1 l))))
  987.        (if v
  988.            (list 'aref
  989.              (f2c-long-name v)
  990.              (f2c-rewrite-symbols context 
  991.                       (f2c-compute-offset v (cddr l))))
  992.          (cons (car l)
  993.            (mapcar (lambda (s)
  994.                  (f2c-rewrite-symbols context s))
  995.                (cdr l))))))
  996.     (t (let ((v (f2c-resolve-ref context (nth 0 l)))); cvt fcns to arefs.
  997.          (if v
  998.          (list 'aref
  999.                (f2c-long-name v)
  1000.                (f2c-rewrite-symbols context 
  1001.                         (f2c-compute-offset v (cdr l))))
  1002.            (cons (car l)
  1003.              (mapcar (lambda (s)
  1004.                    (f2c-rewrite-symbols context s))
  1005.                  (cdr l))))))))
  1006.  
  1007. (defun f2c-all-numbers (l)
  1008.   (or (null l)
  1009.       (and (numberp (car l))
  1010.        (f2c-all-numbers (cdr l)))))
  1011.  
  1012. (defun f2c-reduce (l)
  1013.   (cond ((atom l) l)
  1014.     ((member (car l) '(+ - * /))
  1015.      (let ((red (mapcar 'f2c-reduce (cdr l))))
  1016.        (if (f2c-all-numbers red)
  1017.            (apply (car l) red)
  1018.          (cons (car l) red))))
  1019.     ((and (member (car l) '(progn prog1))
  1020.           (null (cddr l)))
  1021.      (f2c-reduce (cadr l)))
  1022.     (t (cons (car l)
  1023.          (mapcar 'f2c-reduce (cdr l))))))
  1024.  
  1025. (defun f2c-resolve-expr (context expr)
  1026.   "From within CONTEXT, parses EXPR, interpretes variables & reduces the expression.
  1027. Returns a parsed expression."
  1028.   (f2c-reduce (f2c-rewrite-symbols context 
  1029.                    (parcil expr))))
  1030.  
  1031. (defun f2c-resolve-and-expand (context expr)
  1032.   "From within CONTEXT, converts EXPR to a form that GDB will understand.
  1033. Does range expansion."
  1034.   (f2c-expand-ranges (f2c-resolve-expr context expr)))
  1035.  
  1036. (defun f2c-expand-ranges (lexpr)
  1037.   (let* ((globals ())
  1038.      (gcount 0)
  1039.      (ranges ())
  1040.      (symexpr (unparcil (f2c-ranges-to-vars lexpr))))
  1041.     (f2c-expand-ranges-aux globals ranges symexpr)))
  1042.  
  1043. (defun f2c-ranges-to-vars (lexpr)
  1044.   (cond ((atom lexpr) lexpr)
  1045.     ((null lexpr) lexpr)
  1046.     ((eq (car lexpr) ':)
  1047.      (setq globals (cons (f2c-make-global) globals))
  1048.      (setq ranges (cons (cdr lexpr) ranges))
  1049.      (car globals))
  1050.     (t (cons (car lexpr)
  1051.          (mapcar 'f2c-ranges-to-vars
  1052.              (cdr lexpr))))))
  1053.  
  1054. (defun f2c-make-global ()
  1055.   (incf gcount)
  1056.   (concat "__f2cstabsglobal" (number-to-string gcount)))
  1057.  
  1058. (defun f2c-expand-ranges-aux (globals ranges symexpr)
  1059.   (let ((lsymexpr (list symexpr)))
  1060.   (loop for g in globals
  1061.     for r in ranges
  1062.     for start   = (car r)
  1063.     for end     = (cadr r)
  1064.     if (or (not (numberp start))
  1065.            (not (numberp end)))
  1066.     return (error "f2c-expand-ranges-aux:  Ranges must be integers, but found %s:%s." start end)
  1067.     for step    = (if (< start end) 1 -1)
  1068.     for gregexp = (concat ".*\\(" g "\\).*")
  1069.     do (setq lsymexpr (loop for expr in lsymexpr
  1070.                 append (loop for i from start to end by step
  1071.                      if (not (string-match gregexp expr))
  1072.                      return (error "f2c-expand-ranges-aux: Missing iterator variable!")
  1073.                      collect (concat (substring expr 0
  1074.                                     (match-beginning 1))
  1075.                              (number-to-string i)
  1076.                              (substring
  1077.                               expr
  1078.                               (match-end
  1079.                                1))))))
  1080.     finally return lsymexpr)))
  1081.  
  1082.  
  1083. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1084. ;;; High level interface to gdb.
  1085. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1086. (defvar f2c-gdb-history ())
  1087.  
  1088. (defvar f2c-minibuffer-local-map nil
  1089.   "Keymap for minibuffer prompting of f2c-gdb command.")
  1090. (if f2c-minibuffer-local-map
  1091.     ()
  1092.   (setq f2c-minibuffer-local-map (copy-keymap minibuffer-local-map))
  1093.   (define-key
  1094.     f2c-minibuffer-local-map "\C-i" 'f2c-dynamic-complete))
  1095.  
  1096. (defun f2c-dynamic-complete ()
  1097.   "Perform completion in minibuffer on f2c symbol preceding  point."
  1098.   (interactive)
  1099.   (let ((stub ""))
  1100.     (if (string-match "[0-9a-zA-Z_]+$" (buffer-substring (point-min) (point)))
  1101.     (setq stub (buffer-substring (1+ (match-beginning 0)) (1+ (match-end 0)))))
  1102.     (comint-dynamic-simple-complete stub
  1103.                     (mapcar 'symbol-name (f2c-known-vars (gud-context))))))
  1104.  
  1105. (defun f2c-known-vars (context)
  1106.   (let ((cc (f2c-get-or-load-context-stab context)))
  1107.     (apply 'append
  1108.        (cons 
  1109.         (mapcar 'f2c-var-name
  1110.             (f2c-stab-table cc))
  1111.         (mapcar 'f2c-known-vars
  1112.             (f2c-subcontext cc))))))
  1113.     
  1114.  
  1115. (defun f2c-gdb (expr)
  1116.   "Convert Fortran EXPRESSSION to a form that GDB can understand, and
  1117. have gdb evaluate it."
  1118.   (interactive
  1119.    (list (read-from-minibuffer "Evaluate expression: "
  1120.                    (if (consp f2c-gdb-history)
  1121.                    (car f2c-gdb-history)
  1122.                  "")
  1123.                    f2c-minibuffer-local-map nil
  1124.                    '(f2c-gdb-history . 1))))
  1125. ;;; Switch to debugger buffer so that stabs data comes in from correct
  1126. ;;; directory.
  1127.   (gud-set-buffer)            ; Is this needed?
  1128.   (set-buffer gud-comint-buffer)
  1129.   (switch-to-buffer gud-comint-buffer)
  1130.  
  1131. ;;; Note - Must do all resolution before clearing prompt.  This is
  1132. ;;; because resolution can force a call to gud-context, which in turn
  1133. ;;; calls gud-info-command, which expects to see a prompt when the
  1134. ;;; command is done.  If the prompt doesn't come through, it just sits
  1135. ;;; there waiting for more input from the gud process.   Man, did that
  1136. ;;; take a long time to track down...
  1137.   (let* ((context (gud-context))
  1138.      (eval-strings (f2c-resolve-and-expand context expr))
  1139.      (disp-strings (f2c-expand-ranges (f2c-reduce (parcil expr))))
  1140. ;;     (disp-strings eval-strings)
  1141.      )
  1142.     (unwind-protect
  1143.     (progn (gud-basic-call "set prompt\n")
  1144.            (mapcar* 'f2c-gud-print-string
  1145.               disp-strings
  1146.               eval-strings))
  1147.       (gud-send "set prompt (gdb) \n"))))
  1148.  
  1149. (defun f2c-gdb-eval-region (min max)
  1150.   "Convert marked expression to a form that GDB can understand, and
  1151. have gdb evaluate it.  Useful if you come up with some sort of
  1152. f2c-grab-expresion-around-point."
  1153.   (interactive "r")
  1154.   (f2c-gdb (buffer-substring min max)))
  1155.  
  1156. (defun f2c-gdb-snarf ()
  1157.   "Reads expression from current line & gets gdb to print value."
  1158.   (interactive)
  1159.   (f2c-gdb (f2c-snarf)))
  1160.  
  1161.  
  1162. (defun gud-send (s)
  1163.   (process-send-string (get-buffer-process gud-comint-buffer)
  1164.                s))
  1165.  
  1166. (defun f2c-gud-print-nicely (disp strng)
  1167.     (gud-set-buffer)
  1168.     ;; Use gud-basic-call to remove prompt & turn off prompting!
  1169.     (unwind-protect
  1170.     (progn (gud-basic-call "set prompt\n")
  1171.            (f2c-gud-print-string disp strng))
  1172.       (gud-send "set prompt (gdb) \n")))
  1173.  
  1174. (defun f2c-gud-print-string (disp strng)
  1175.   (gud-send (format "echo %s = \n" disp))
  1176.   (gud-send (format "output %s\n" strng))
  1177.   (gud-send "echo \\n\n"))
  1178.  
  1179.   
  1180.  
  1181. (defun f2c-gud-print (var-data ref)
  1182.   (cond ((or (null ref)
  1183.          (null (f2c-dimen var-data))
  1184.          (null (f2c-aref var-data)))
  1185.      ;; Just a simple variable!!!
  1186.      (gud-send (format "echo %s = \n" (f2c-var-name var-data)))
  1187.      (gud-send (format "output %s\n" (f2c-long-name var-data))))
  1188.     (t
  1189.      ;; An array reference.
  1190.      (gud-send (format "echo %s%s = \n"
  1191.                (f2c-var-name var-data)
  1192.                ref))
  1193.      (gud-send (format "output %s[%s]\n"
  1194.                (f2c-long-name var-data)
  1195.                (f2c-compute-offset var-data ref)))))
  1196.   (gud-send "echo \\n\n"))
  1197.  
  1198. (defun f2c-compute-offset (var-data ref)
  1199.   (funcall (f2c-aref var-data)
  1200.        (f2c-dimen var-data)
  1201.        ref
  1202.        (f2c-offset var-data)))
  1203.  
  1204. (provide 'f2c-stabs)
  1205.